﻿#pragma once

#include "../box/proc_stat.hh"
#include "../detail/box_config_impl.hh"
#include <any>
#include <ctime>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <thread>
#include <unordered_map>

namespace kratos {
namespace config {
class BoxConfig;
}
} // namespace kratos

namespace kratos {
namespace service {

class ServiceBox;

/**
 * 属性类型.
 */
enum class ValueType : std::int32_t {
  CPU_USAGE = 1,    ///< CPU使用率
  MEM_OCCUPY_K,     ///< 内存使用量(K)
  MEM_OCCUPY_M,     ///< 内存使用量(M)
  PID_FILE,         ///< PID文件
  DAEMON,           ///< 是否是daemon
  CONFIG_FILE_PATH, ///< 配置文件名
  LAST_SLOT,
  MAX_SLOT,
};

class ProcStatImpl;

/**
 * 进程信息模块接口.
 */
class ProcStatModule {
public:
  /**
   * 析构.
   *
   */
  virtual ~ProcStatModule() {}
  /**
   * 启动.
   *
   * \param process 进程信息实现类
   * \return true或false
   */
  virtual auto start(ProcStatImpl *process) -> bool = 0;
  /**
   * 停止.
   *
   * \return
   */
  virtual auto stop() -> void = 0;
  /**
   * 主循环.
   *
   * \param tick
   * \return
   */
  virtual auto update(std::time_t tick) -> void = 0;
};

/**
 * ProcStat实现类.
 */
class ProcStatImpl : public ProcStat {
  ValueMap value_map_; ///< {属性名，属性值}
  std::thread worker_; ///< 工作线程，模块update在这个线程内运行
  std::mutex value_map_mutex_; ///< 属性表锁
  bool running_{true};         ///< 工作线程运行标志
  std::string report_api_;     ///< 统计信息汇报接口
  std::string report_host_;    ///< 统计信息汇报主机地址
  ServiceBox *box_{nullptr};   ///< 服务容器

public:
  /**
   * 构造.
   *
   */
  ProcStatImpl();
  /**
   * 析构.
   *
   */
  virtual ~ProcStatImpl();
  virtual auto get_value(const std::string &name, std::string &value)
      -> bool override;
  virtual auto get(ValueMap &value_map) -> bool override;

public:
  /**
   * 启动, 启动所有组件并启动工作线程.
   *
   * \param box 服务容器
   * \return true或false
   */
  auto start(ServiceBox *box) -> bool;
  /**
   * 关闭工作线程并关闭所有组件.
   *
   * \return true或false
   */
  auto stop() -> bool;
  /**
   * 添加模块.
   *
   * \param name 模块名
   * \param module 模块
   * \return
   */
  auto add_module(const std::string &name, ProcStatModule *module) -> bool;
  /**
   * 更改属性值.
   *
   * \param name 属性名
   * \param value 属性值
   * \return
   */
  auto update_value(const std::string &name, const std::string &value) -> void;
  /**
   * 更改属性值.
   *
   * \param type 属性类型
   * \param value 属性值
   * \return
   */
  auto update_array_value(ValueType type, std::any &&value) -> void;
  /**
   * 获取属性值.
   *
   * \param type
   * \return
   */
  template <typename T> auto get_value_any(ValueType type) {
    const auto &any = get_value_any_internal(type);
    if (!any.has_value()) {
      // Should never happen
      throw std::runtime_error("Invalid attribute type");
    }
    return std::any_cast<T>(any);
  }
  /**
   * 获取服务容器.
   * 
   * \return 
   */
  auto get_box() -> ServiceBox *;

private:
  /**
   * 从内部快查表获取属性.
   *
   * \param type 属性类型
   * \return std::any
   */
  auto get_value_any_internal(ValueType type) -> const std::any &;
  /**
   * 加载配置.
   *
   * \return
   */
  auto load_config() -> bool;
  /**
   * 更新固定的属性.
   * 
   * \return 
   */
  auto update_fixed_value() -> void;
};

} // namespace service
} // namespace kratos
